package com.bckj.fastboot.core.extra.txasync;

import com.bckj.fastboot.core.extra.txasync.constant.TxAsyncConstants;
import com.bckj.fastboot.core.jackson.JsonUtils;
import com.bckj.fastboot.core.extra.txasync.constant.TxAsyncEnum;
import com.bckj.fastboot.core.extra.txasync.entity.AsyncInvocation;
import com.bckj.fastboot.core.extra.txasync.entity.AsyncInvocationBuilder;
import com.bckj.fastboot.core.extra.txasync.service.AsyncInvocationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Slf4j
@Aspect
@RequiredArgsConstructor
public class TxAsyncAspect {
    private final AsyncInvocationService asyncInvocationService;

    @Around("@annotation(txAsync)")
    public Object around(ProceedingJoinPoint joinPoint, TxAsync txAsync) {
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            throw new RuntimeException("The args is not null");
        }
        if (args.length != 1) {
            throw new RuntimeException("The args length must be 1");
        }
        if (args[0] instanceof TxAsyncParam param) {
            // 手动执行重试
            if (param.getRetryFlag() == TxAsyncConstants.RETRY_FLAG_RETRYING) {
                try {
                    return joinPoint.proceed();
                } catch (Throwable e) {
                    throw new RuntimeException(e);
                }
            } else {
                AsyncInvocation asyncInvocation = assembleAsyncInvocation(joinPoint, param, txAsync);
                asyncInvocationService.execute(asyncInvocation, () -> {
                    try {
                        joinPoint.proceed();
                    } catch (Throwable e) {
                        throw new RuntimeException(e);
                    }
                });
            }
        } else {
            throw new RuntimeException("The first parameter must be of type TxAsyncParam");
        }
        return null;
    }

    AsyncInvocation assembleAsyncInvocation(ProceedingJoinPoint joinPoint, TxAsyncParam param, TxAsync txAsync) {
        return new AsyncInvocationBuilder()
                .taskId(txAsync.taskIdPrefix() + param.getTaskId())
                .taskName(txAsync.taskName())
                .timeout(txAsync.timeout())
                .maxAttempt(txAsync.maxAttempt())
                .multiplier(txAsync.multiplier())
                .methodName(joinPoint.getSignature().getName())
                .className(joinPoint.getTarget().getClass().getName())
                .params(JsonUtils.toJsonStr(param))
                .status(TxAsyncEnum.READY.getCode())
                .build();
    }
}
